﻿#region zh-CHS 2006 - 2010 DemoSoft 团队 | en 2006-2010 DemoSoft Team

//     NOTES
// ---------------
//
// This file is a part of the MMOSE(Massively Multiplayer Online Server Engine) for .NET.
//
//                              2006-2010 DemoSoft Team
//
//
// First Version : by H.Q.Cai - mailto:caihuanqing@hotmail.com

/***************************************************************************
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU Lesser General Public License as published
 *   by the Free Software Foundation; either version 2.1 of the License, or
 *   (at your option) any later version.
 *
 ***************************************************************************/

#region zh-CHS 包含名字空间 | en Include namespace
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using System.Threading;
using Demo.Mmose.Core.Common;
#endregion

namespace Demo.Mmose.Core.Common.SafeCollections
{
    /// <summary>
    /// 
    /// </summary>
    public class SafeLinkedList<ValueT> : IEnumerable<ValueT>
    {
        #region zh-CHS 构造和初始化和清理 | en Constructors and Initializers and Dispose
        /// <summary>
        /// 
        /// </summary>
        public SafeLinkedList()
        {
            m_LinkedList = new LinkedList<ValueT>();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="collection"></param>
        public SafeLinkedList( IEnumerable<ValueT> collection )
        {
            m_LinkedList = new LinkedList<ValueT>( collection );
        }
        #endregion

        #region zh-CHS 共有属性 | en Public Properties
        /// <summary>
        /// 
        /// </summary>
        public int Count
        {
            get { return m_LinkedList.Count; }
        }

        /// <summary>
        /// 
        /// </summary>
        public LinkedListNode<ValueT> First
        {
            get
            {
                LinkedListNode<ValueT> linkedListNode = null;

                m_LockLinkedList.EnterReadLock();
                try
                {
                    linkedListNode = m_LinkedList.First;
                }
                finally
                {
                    m_LockLinkedList.ExitReadLock();
                }

                return linkedListNode;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public LinkedListNode<ValueT> Last
        {
            get
            {
                LinkedListNode<ValueT> linkedListNode = null;

                m_LockLinkedList.EnterReadLock();
                try
                {
                    linkedListNode = m_LinkedList.Last;
                }
                finally
                {
                    m_LockLinkedList.ExitReadLock();
                }

                return linkedListNode;
            }
        }
        #endregion

        #region zh-CHS 共有方法 | en Public Methods

        #region zh-CHS 私有成员变量 | en Private Member Variables
        /// <summary>
        /// 
        /// </summary>
        private LinkedList<ValueT> m_LinkedList = null;
        /// <summary>
        /// 
        /// </summary>
        private ReaderWriterLockSlim m_LockLinkedList = new ReaderWriterLockSlim();
        #endregion
        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="newNode"></param>
        public void AddAfter( LinkedListNode<ValueT> node, LinkedListNode<ValueT> newNode )
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.AddAfter( node, newNode );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public LinkedListNode<ValueT> AddAfter( LinkedListNode<ValueT> node, ValueT value )
        {
            LinkedListNode<ValueT> linkedListNode = null;

            m_LockLinkedList.EnterWriteLock();
            try
            {
                linkedListNode = m_LinkedList.AddAfter( node, value );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }

            return linkedListNode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="newNode"></param>
        public void AddBefore( LinkedListNode<ValueT> node, LinkedListNode<ValueT> newNode )
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.AddBefore( node, newNode );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public LinkedListNode<ValueT> AddBefore( LinkedListNode<ValueT> node, ValueT value )
        {
            LinkedListNode<ValueT> linkedListNode = null;

            m_LockLinkedList.EnterWriteLock();
            try
            {
                linkedListNode = m_LinkedList.AddBefore( node, value );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }

            return linkedListNode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        public void AddFirst( LinkedListNode<ValueT> node )
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.AddFirst( node );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public LinkedListNode<ValueT> AddFirst( ValueT value )
        {
            LinkedListNode<ValueT> linkedListNode = null;

            m_LockLinkedList.EnterWriteLock();
            try
            {
                linkedListNode = m_LinkedList.AddFirst( value );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }

            return linkedListNode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        public void AddLast( LinkedListNode<ValueT> node )
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.AddLast( node );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public LinkedListNode<ValueT> AddLast( ValueT value )
        {
            LinkedListNode<ValueT> linkedListNode = null;

            m_LockLinkedList.EnterWriteLock();
            try
            {
                linkedListNode = m_LinkedList.AddLast( value );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }

            return linkedListNode;
        }

        /// <summary>
        /// 
        /// </summary>
        public void Clear()
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.Clear();

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Contains( ValueT value )
        {
            bool returnBool = false;

            m_LockLinkedList.EnterReadLock();
            try
            {
                returnBool = m_LinkedList.Contains( value );
            }
            finally
            {
                m_LockLinkedList.ExitReadLock();
            }

            return returnBool;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="array"></param>
        /// <param name="index"></param>
        public void CopyTo( ValueT[] array, int index )
        {
            m_LockLinkedList.EnterReadLock();
            try
            {
                m_LinkedList.CopyTo( array, index );
            }
            finally
            {
                m_LockLinkedList.ExitReadLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public LinkedListNode<ValueT> Find( ValueT value )
        {
            LinkedListNode<ValueT> linkedListNode = null;

            m_LockLinkedList.EnterReadLock();
            try
            {
                linkedListNode = m_LinkedList.Find( value );
            }
            finally
            {
                m_LockLinkedList.ExitReadLock();
            }

            return linkedListNode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public LinkedListNode<ValueT> FindLast( ValueT value )
        {
            LinkedListNode<ValueT> linkedListNode = null;

            m_LockLinkedList.EnterReadLock();
            try
            {
                linkedListNode = m_LinkedList.FindLast( value );
            }
            finally
            {
                m_LockLinkedList.ExitReadLock();
            }

            return linkedListNode;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="node"></param>
        public void Remove( LinkedListNode<ValueT> node )
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.Remove( node );

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public bool Remove( ValueT value )
        {
            bool returnBool = false;

            m_LockLinkedList.EnterWriteLock();
            try
            {
                returnBool = m_LinkedList.Remove( value );

                if ( returnBool == true )
                    m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }

            return returnBool;
        }

        /// <summary>
        /// 
        /// </summary>
        public void RemoveFirst()
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.RemoveFirst();

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }


        /// <summary>
        /// 
        /// </summary>
        public void RemoveLast()
        {
            m_LockLinkedList.EnterWriteLock();
            try
            {
                m_LinkedList.RemoveLast();

                m_bIsValueChange = true;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }
        }

        #region zh-CHS 私有成员变量 | en Private Member Variables
        #region zh-CHS 私有常量 | en Private Constants
        /// <summary>
        /// 
        /// </summary>
        private readonly static ValueT[] s_ZeroValueArray = new ValueT[0];
        #endregion
        /// <summary>
        /// 
        /// </summary>
        private volatile ValueT[] m_ValueArray = s_ZeroValueArray;
        /// <summary>
        /// 
        /// </summary>
        private volatile bool m_bIsValueChange = true;
        #endregion

        #region zh-CHS 私有方法 | en Private Methods
        /// <summary>
        /// 
        /// </summary>
        private void InternalToCached()
        {
            if ( m_bIsValueChange == false )
                return;

            m_LockLinkedList.EnterReadLock();
            try
            {
                if ( m_bIsValueChange == true )
                {
                    m_ValueArray = new ValueT[m_LinkedList.Count];

                    int iIndex = 0;
                    foreach ( ValueT keyValuePair in m_LinkedList )
                    {
                        m_ValueArray[iIndex] = keyValuePair;
                        ++iIndex;
                    }

                    // 最后设置
                    m_bIsValueChange = false;
                }
            }
            finally
            {
                m_LockLinkedList.ExitReadLock();
            }
        }
        #endregion
        /// <summary>
        /// 这里假设读非常多，写比较少。 
        /// </summary>
        /// <returns></returns>
        [MultiThreadedWarning( "zh-CHS", "当前的数组是列表临时产生的,不能保存数组用于以后操作:警告!" )]
        public ValueT[] ToArray()
        {
            InternalToCached();

            return m_ValueArray;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ValueT[] ToArrayAndClear()
        {
            ValueT[] valueArray = s_ZeroValueArray;

            m_LockLinkedList.EnterWriteLock();
            try
            {
                if ( m_bIsValueChange == true )
                {
                    valueArray = new ValueT[m_LinkedList.Count];

                    int iIndex = 0;
                    foreach ( ValueT keyValuePair in m_LinkedList )
                    {
                        valueArray[iIndex] = keyValuePair;
                        ++iIndex;
                    }

                    // 最后设置
                    m_bIsValueChange = false;
                }
                else
                    valueArray = m_ValueArray;

                // 清空
                m_LinkedList.Clear();
                m_ValueArray = s_ZeroValueArray;
            }
            finally
            {
                m_LockLinkedList.ExitWriteLock();
            }

            return valueArray;
        }

        #endregion

        #region zh-CHS 接口实现 | en Interface Implementation
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IEnumerator<ValueT> GetEnumerator()
        {
            ValueT[] tempValueArray = this.ToArray();
            if ( tempValueArray == null )
                yield break;

            for ( int iIndex = 0; iIndex < tempValueArray.Length; iIndex++ )
                yield return tempValueArray[iIndex];
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
        #endregion
    }
}
#endregion